#pragma once

namespace AVUI {
             
/// <summary>Provides static helper methods for logical tree element queries.</summary>
class LogicalTreeHelper
{
public:
#pragma region Public Methods

    /// <summary>Attempts to bring the requested element into view and raises the <see cref="E:System.Windows.FrameworkElement.RequestBringIntoView" /> event on the target in order to report the results.</summary>
    /// <returns />
    /// <param name="current">The element to bring into view.</param>
    static void BringIntoView(DependencyObject* pCurrent);

    /// <summary>Attempts to find and return an element node that has the specified name. The search starts from the specified element and continues into subnodes. </summary>
    /// <returns>The element with the matching name, if one is found; returns null if no matching name was found in the active namescope.</returns>
    /// <param name="logicalTreeNode">The element to start searching from. This object must be either a <see cref="T:System.Windows.FrameworkElement" /> or <see cref="T:System.Windows.FrameworkContentElement" /> type.</param>
    /// <param name="elementName">The name of the element node to find.</param>
    static DependencyObject* FindLogicalNode(DependencyObject* pLogicalTreeNode, String* pElementName);

    /// <summary>Returns the collection of immediate child elements from the logical tree of the specified element.</summary>
    /// <returns>The enumerable collection of immediate child elements from the logical tree of the specified element.</returns>
    /// <param name="current">The element from which to get the logical tree. This is expected to be either a <see cref="T:System.Windows.FrameworkElement" /> or <see cref="T:System.Windows.FrameworkContentElement" />.</param>
    static TRefCountedPtr<Object> GetChildren(DependencyObject* pCurrent);

    /// <summary>Returns the collection of immediate child elements from the logical tree of the specified <see cref="T:System.Windows.FrameworkContentElement" />. </summary>
    /// <returns>The enumerable collection of immediate child elements from the logical tree of the specified input element.</returns>
    /// <param name="current">The element from which to get the logical tree.</param>
    static TRefCountedPtr<Object> GetChildren(FrameworkContentElement* pCurrent);

    /// <summary>Returns the collection of immediate child elements from the logical tree of the specified <see cref="T:System.Windows.FrameworkElement" />. </summary>
    /// <returns>The enumerable collection of immediate child elements from the logical tree of the specified input element.</returns>
    /// <param name="current">The element from which to get the logical tree.</param>
    static TRefCountedPtr<Object> GetChildren(FrameworkElement* pCurrent);

    /// <summary>Returns the logical parent element of the specified element.</summary>
    /// <returns>The requested parent element.</returns>
    /// <param name="current">The element to find the parent for. This is expected to be either <see cref="T:System.Windows.FrameworkElement" /> or <see cref="T:System.Windows.FrameworkContentElement" />.</param>
    static DependencyObject* GetParent(DependencyObject* pCurrent);

#pragma endregion Public Methods

public:

#pragma region Internal Methods

    static void AddLogicalChild(DependencyObject* pParent, Object* pChild);
    static void AddLogicalChild(FrameworkElement* pParentFE, FrameworkContentElement* pParentFCE, Object* pChild);
    static TRefCountedPtr<Object> GetLogicalChildren(DependencyObject* pCurrent);
    static void RemoveLogicalChild(DependencyObject* pParent, Object* pChild);
    static void RemoveLogicalChild(FrameworkElement* pParentFE, FrameworkContentElement* pParentFCE, Object* pChild);

#pragma endregion Internal Methods

};

#pragma region Private Helper

class EnumeratorWrapper : public Object, public IEnumerable
{
public:
    DECLARE_ELEMENT(EnumeratorWrapper, Object);

    EnumeratorWrapper(Object* pEnumerator)
    {
        if(pEnumerator != NULL)
        {
            m_pEnumeratorObject = pEnumerator;
        }
        else
        {
            m_pEnumeratorObject = EmptyEnumerator::get_Instance();
        }
    }

    virtual ObjectPtr GetEnumerator() AVUI_OVERRIDE { return m_pEnumeratorObject; }
    virtual Object* get_Object() { return this; }

    static EnumeratorWrapper* get_Empty()
    {
        static EnumeratorWrapper emptyEnumeratorWrapper(NULL);
        return &emptyEnumeratorWrapper;
    }

private:
    TRefCountedPtr<Object> m_pEnumeratorObject;
};

#pragma endregion Private Helper


}; // namespace AVUI


